package main

import (
	"encoding/csv"
	"encoding/json"
	"flag"
	"fmt"
	"github.com/makiuchi-d/gozxing/oned"
	"image"
	_ "image/jpeg"
	_ "image/png"
	"os"
	"path/filepath"
	"strings"

	"github.com/makiuchi-d/gozxing"
	"github.com/makiuchi-d/gozxing/qrcode"
)

// Result 存储识别结果的结构
type Result struct {
	ImagePath string   `json:"image_path"` // 图片路径
	Barcodes  []string `json:"barcodes"`   // 识别到的条码列表
}

var (
	imageDir    = flag.String("dir", "", "包含图片的目录路径")
	outputFile  = flag.String("out", "barcodes.json", "输出结果文件")
	queryCode   = flag.String("query", "", "查询条码并显示相关信息")
	displayMode = flag.Bool("display", false, "查询时显示图片路径")
	csvOutput   = flag.Bool("csv", false, "输出CSV格式结果")
)

func main() {
	flag.Parse()

	if *imageDir != "" {
		results, err := processImages(*imageDir)
		if err != nil {
			fmt.Printf("处理图片失败: %v\n", err)
			os.Exit(1)
		}

		if *csvOutput {
			err = saveAsCSV(results, *outputFile)
		} else {
			err = saveAsJSON(results, *outputFile)
		}

		if err != nil {
			fmt.Printf("保存结果失败: %v\n", err)
			os.Exit(1)
		}
		fmt.Printf("成功处理 %d 张图片，结果保存到 %s\n", len(results), *outputFile)
	} else if *queryCode != "" {
		results, err := loadResults(*outputFile)
		if err != nil {
			fmt.Printf("加载结果失败: %v\n", err)
			os.Exit(1)
		}

		queryResults(results, *queryCode, *displayMode)
	} else {
		fmt.Println("请指定操作模式:")
		fmt.Println("  扫描图片: -dir <图片目录> [-out 输出文件]")
		fmt.Println("  查询条码: -query <条码内容> [-out 结果文件] [-display]")
		fmt.Println("选项:")
		flag.PrintDefaults()
	}
}

// 处理目录中的所有图片
func processImages(dir string) ([]Result, error) {
	var results []Result

	files, err := os.ReadDir(dir)
	if err != nil {
		return nil, err
	}

	for _, file := range files {
		if file.IsDir() {
			continue
		}

		ext := strings.ToLower(filepath.Ext(file.Name()))
		if ext != ".jpg" && ext != ".jpeg" && ext != ".png" {
			continue
		}

		path := filepath.Join(dir, file.Name())
		codes, err := decodeBarcodes(path)
		if err != nil {
			fmt.Printf("跳过 %s: %v\n", path, err)
			continue
		}

		if len(codes) > 0 {
			results = append(results, Result{
				ImagePath: path,
				Barcodes:  codes,
			})
			fmt.Printf("识别成功: %s -> %v\n", path, codes)
		} else {
			fmt.Printf("未识别到条码: %s\n", path)
		}
	}

	return results, nil
}

// 识别图片中的条码
func decodeBarcodes(imagePath string) ([]string, error) {
	file, err := os.Open(imagePath)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	img, _, err := image.Decode(file)
	if err != nil {
		return nil, err
	}

	// 准备条码识别器
	source := gozxing.NewLuminanceSourceFromImage(img)
	binarizer := gozxing.NewHybridBinarizer(source)
	bitmap, err := gozxing.NewBinaryBitmap(binarizer)
	if err != nil {
		return nil, err
	}
	results := []string{}
	// 配置解码参数
	hints := map[gozxing.DecodeHintType]interface{}{
		gozxing.DecodeHintType_TRY_HARDER: true,
		gozxing.DecodeHintType_POSSIBLE_FORMATS: []gozxing.BarcodeFormat{
			gozxing.BarcodeFormat_QR_CODE,
			gozxing.BarcodeFormat_CODE_39,
			gozxing.BarcodeFormat_DATA_MATRIX,
			gozxing.BarcodeFormat_CODE_128,
			gozxing.BarcodeFormat_EAN_13,
			gozxing.BarcodeFormat_UPC_A,
			gozxing.BarcodeFormat_ITF,
		},
	}
	// 尝试多种识别器
	readers := []gozxing.Reader{
		oned.NewMultiFormatUPCEANReader(hints),
		oned.NewCode128Reader(),
		oned.NewCode39Reader(),
		oned.NewITFReader(),
		qrcode.NewQRCodeReader(),
	}
	for _, reader := range readers {
		result, err := reader.Decode(bitmap, hints)
		if err == nil {
			results = append(results, result.GetText())
		}
	}

	return uniqueStrings(results), nil
}
func uniqueStrings(input []string) []string {
	keys := make(map[string]bool)
	list := []string{}
	for _, item := range input {
		if _, value := keys[item]; !value {
			keys[item] = true
			list = append(list, item)
		}
	}
	return list
}

// 保存为JSON
func saveAsJSON(results []Result, filename string) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	encoder := json.NewEncoder(file)
	encoder.SetIndent("", "  ")
	return encoder.Encode(results)
}

// 保存为CSV
func saveAsCSV(results []Result, filename string) error {
	file, err := os.Create(filename)
	if err != nil {
		return err
	}
	defer file.Close()

	writer := csv.NewWriter(file)
	defer writer.Flush()

	// 写入表头
	if err := writer.Write([]string{"image_path", "barcodes"}); err != nil {
		return err
	}

	// 写入数据
	for _, result := range results {
		barcodes := strings.Join(result.Barcodes, "|")
		if err := writer.Write([]string{result.ImagePath, barcodes}); err != nil {
			return err
		}
	}

	return nil
}

// 加载结果
func loadResults(filename string) ([]Result, error) {
	file, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer file.Close()

	var results []Result
	if strings.HasSuffix(filename, ".csv") {
		reader := csv.NewReader(file)
		records, err := reader.ReadAll()
		if err != nil {
			return nil, err
		}

		for i, record := range records {
			if i == 0 { // 跳过表头
				continue
			}
			if len(record) < 2 {
				continue
			}
			barcodes := strings.Split(record[1], "|")
			results = append(results, Result{
				ImagePath: record[0],
				Barcodes:  barcodes,
			})
		}
	} else {
		decoder := json.NewDecoder(file)
		if err := decoder.Decode(&results); err != nil {
			return nil, err
		}
	}

	return results, nil
}

// 查询条码
func queryResults(results []Result, code string, display bool) {
	found := false

	for _, result := range results {
		for _, b := range result.Barcodes {
			if b == code {
				fmt.Printf("找到条码: %s\n", code)
				fmt.Printf("图片路径: %s\n", result.ImagePath)
				fmt.Printf("同图其他条码: %v\n", result.Barcodes)
				fmt.Println("------")
				found = true

				if display {
					fmt.Printf("显示图片命令: open \"%s\" (Mac)\n", result.ImagePath)
					fmt.Printf("            xdg-open \"%s\" (Linux)\n", result.ImagePath)
					fmt.Printf("            start \"\" \"%s\" (Windows)\n", result.ImagePath)
				}
				break
			}
		}
	}

	if !found {
		fmt.Printf("未找到条码: %s\n", code)
	}
}
